package com.jgp.security.service;

import com.jgp.common.type.RoleType;
import com.jgp.security.annotation.Power;
import com.jgp.security.config.SecUserAdapter;
import com.jgp.security.props.SecurityConfigPropBean;
import com.jgp.security.secmodel.SecInstitution;
import com.jgp.security.secmodel.SecInstitutionUser;
import com.jgp.security.secmodel.SecUser;
import com.jgp.security.secrepository.SecUserRepository;
import com.jgp.sys.annotation.PowerGroup;
import com.jgp.sys.query.Operator;
import com.jgp.sys.query.OrderDirection;
import com.jgp.sys.query.OrderList;
import com.jgp.sys.query.QueryFilterList;
import com.jgp.sys.ui.Pager;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2019-11-02
 */
@PowerGroup("用户管理")
@Service
@Transactional(transactionManager = "secondTransactionManager", readOnly = true)
public class SecUserService {
	@Lazy
	@Autowired
	private SecUserRepository repository;
	
	@Autowired
	private SecUserAdapter userAdapter;
	
	@Autowired
	private SecurityConfigPropBean securityConfigPropBean;
	
	@Autowired
	private SecInstitutionService institutionService;
	
	@Autowired
	private SecInstitutionUserService institutionUserService;
	
	private SecUser SUPER_ADMIN;
	
	@Autowired
	private SecRoleUserService secRoleUserService;
	
	@PostConstruct
	private void initSuperAdmin() {
		String superAdminInfo = securityConfigPropBean.getSuperAdmin();
		if (StringUtils.isNotBlank(securityConfigPropBean.getSuperAdmin())) {
			SUPER_ADMIN = new SecUser();
			SUPER_ADMIN.setId("bbd8a2fa40c6448d888bcf05b8715df4");
			SUPER_ADMIN.setRealName("超级管理员");
			SUPER_ADMIN.setLocked(false);
			SUPER_ADMIN.setDelFlag(false);
			String[] infos = superAdminInfo.split(",");
			SUPER_ADMIN.setUsername(infos[0]);
			try {
				if (infos.length == 1) {
					SUPER_ADMIN = userAdapter.operatorPwd(SUPER_ADMIN, "");
				} else if (infos.length == 2) {
					SUPER_ADMIN = userAdapter.operatorPwd(SUPER_ADMIN, infos[1]);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			SUPER_ADMIN = null;
		}
	}
	
	public SecUser getSuperAdmin() {
		return SUPER_ADMIN;
	}
	
	@Power(remark = "保持用户")
	@Transactional(transactionManager = "secondTransactionManager")
	public void saveSystemAdmin(SecUser user) {
		user.setType(RoleType.SYS_ADMIN);
		repository.createOrUpdate(user);
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public void saveSystemUser(SecUser user) {
		user.setType(RoleType.SYS_USER);
		repository.createOrUpdate(user);
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public SecUser saveUser(SecUser user) {
		return repository.createOrUpdate(user);
	}
	
	/**
	 * 根据账号查询用户
	 *
	 * @param account 用户名、电话、邮箱
	 * @return
	 */
	public SecUser queryByAccount(String account) {
		SecUser user = null;
		if (StringUtils.isNotBlank(account)) {
			
			if (account.equals(SUPER_ADMIN.getUsername())) {
				user = SUPER_ADMIN;
			} else {
				List<SecUser> users = repository.findByUsernameOrTelOrEmail(account, account, account);
				if (Objects.isNull(users) || users.size() == 0) return null;
				user = users.stream().filter(u -> !u.getDelFlag()).findFirst().orElse(null);
			}
			
		}
		
		return user;
	}
	
	public SecUser query(String id) {
		return repository.read(id);
	}
	
	public List<SecUser> query(List<String> ids) {
		return repository.read(ids);
	}
	
	public List<SecUser> querySystemAdmin(String realName, String username, String tel, String email, Boolean locked, Pager pager) {
		return query(null, realName, username, tel, email, locked, RoleType.SYS_ADMIN, pager);
	}
	
	public List<SecUser> querySystemUser(
			Long institutionId, String realName, String username, String tel, String email, Boolean locked, Pager pager) {
		return query(institutionId, realName, username, tel, email, locked, RoleType.SYS_USER, pager);
	}
	
	public List<SecUser> query(
			Long institutionId, String realName, String username, String tel, String email, Boolean locked, RoleType type, Pager pager) {
		QueryFilterList filters = filters(realName, username, tel, email, locked, type);
		OrderList orders = new OrderList();
		orders.addOrder("createTimestamp", OrderDirection.DESC);
		if (Objects.nonNull(institutionId)) {
			List<SecInstitution> institutions = Arrays.asList(new SecInstitution[]{institutionService.queryOne(institutionId)});
			List<SecInstitution> downs = institutionService.queryDown(institutions);
			downs.addAll(institutions);
			List<Long> ids = downs.stream().map(SecInstitution::getId).distinct().collect(Collectors.toList());
			return repository.read(filters, orders, (root, query, builder) -> {
				Subquery<SecInstitutionUser> subquery = query.subquery(SecInstitutionUser.class);
				Root<SecInstitutionUser> subRoot = subquery.from(SecInstitutionUser.class);
				subquery.select(subRoot);
				Predicate p = builder.equal(subRoot.get("userId"), root.get("id"));
				Predicate p2 = subRoot.get("institutionId").in(ids);
				subquery.where(p, p2);
				return builder.and(builder.exists(subquery.where(p, p2)));
			}, pager);
		} else {
			return repository.read(filters, orders, pager);
		}
		
	}
	
	private QueryFilterList filters(String realName, String username, String tel, String email, Boolean locked, RoleType type) {
		QueryFilterList filters = new QueryFilterList();
		if (StringUtils.isNotBlank(realName)) filters.addFilter("realName", Operator.like, realName);
		if (StringUtils.isNotBlank(username)) filters.addFilter("username", Operator.like, username);
		if (StringUtils.isNotBlank(tel)) filters.addFilter("tel", Operator.likeL, tel);
		if (StringUtils.isNotBlank(email)) filters.addFilter("email", Operator.like, email);
		if (Objects.nonNull(locked)) filters.addFilter("locked", Operator.eq, locked);
		if (Objects.nonNull(type)) filters.addFilter("type", Operator.eq, type);
		return filters;
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public void removeUser(List<String> ids) {
		QueryFilterList filters = new QueryFilterList();
		filters.addFilter("id", Operator.in, ids);
		// filters.addFilter("type", Operator.eq, RoleType.SYS_ADMIN);
		repository.delete(filters);
		secRoleUserService.deleteByUserId(ids);
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public void lockUser(String id) {
		SecUser user = repository.read(id);
		user.setLocked(true);
		repository.update(user);
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public SecUser setThirdOpenId(String userId, String thirdOpenId) {
		SecUser user = repository.read(userId);
		user.setThirdOpenId(thirdOpenId);
		return repository.update(user);
	}
	
	public SecUser queryByThirdOpenId(String thirdOpenId) {
		QueryFilterList filters = new QueryFilterList();
		filters.addFilter("thirdOpenId", Operator.eq, thirdOpenId);
		repository.readOne(filters);
		return repository.readOne(filters);
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public void unLockUser(String id) {
		SecUser user = repository.read(id);
		user.setLocked(false);
		repository.update(user);
	}
	
	/**
	 * 系统重置密码
	 *
	 * @param id  用户ID
	 * @param pwd 新密码
	 */
	@Transactional(transactionManager = "secondTransactionManager")
	public void resetPassword(String id, String pwd) {
		SecUser user = repository.read(id);
		try {
			user = userAdapter.operatorPwd(user, pwd);
		} catch (IOException e) {
			e.printStackTrace();
		}
		repository.update(user);
	}
	
	
	@Transactional(transactionManager = "secondTransactionManager")
	public void lock(String userId) {
		SecUser user = repository.read(userId);
		user.setLocked(true);
		repository.update(user, "locked");
	}
	
	@Transactional(transactionManager = "secondTransactionManager")
	public void unLock(String userId) {
		SecUser user = repository.read(userId);
		user.setLocked(false);
		repository.update(user, "locked");
	}
	
	/**
	 * 新增用户，更新default_institution_id
	 *
	 * @param id     用户ID
	 * @param instId 机构id
	 */
	@Transactional(transactionManager = "secondTransactionManager")
	public void updateDefaultInstitutionId(String id, Long instId) {
		SecUser user = repository.read(id);
		user.setDefaultInstitutionId(instId);
		repository.update(user);
	}
	
	/**
	 * 人员调转
	 *
	 * @param mode
	 * @param userId
	 * @param institutionIds
	 */
	@Transactional(transactionManager = "secondTransactionManager")
	public void userTransferTo(String mode, String userId, List<Long> institutionIds) {
		SecUser user = query(userId);
		if (Objects.nonNull(user.getTransfer()) && user.getTransfer()) {
			if (StringUtils.isNotBlank(user.getTransferFrom())) {
				throw new RuntimeException("已内部调岗，如需再次调岗，请先调回");
			} else {
				throw new RuntimeException("已调出，如需调岗，请先调回");
			}
		}
  
		repository.deletePersist(user);
		
        try {
            SecUser newUser = (SecUser)user.clone();
            newUser.setId(null);
            newUser.setTransfer(true);
            newUser.setDefaultInstitutionId(null);
            if (mode.equals("move")) {
                newUser.setTransferFrom(userId);
            }
    
            SecUser newPersistUser = saveUser(newUser);
    
            if (mode.equals("move")) {
                institutionUserService.modifyUserInstitution(newPersistUser.getId(), institutionIds);
            }
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
	}
	
	/**
	 * 人员调回
	 *
	 * @param userId
	 */
	@Transactional(transactionManager = "secondTransactionManager")
	public void userTransferBack(String userId) {
        SecUser user = query(userId);
        if (Objects.isNull(user.getTransfer()) || !user.getTransfer()) {
            throw new RuntimeException("没有调岗，无需调回");
        }
        repository.delete(user);
        try {
            SecUser newUser = (SecUser)user.clone();
            newUser.setId(user.getTransferFrom());
            newUser.setTransferFrom(null);
            newUser.setTransfer(false);
            repository.create(newUser);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
	}
}
